;;; Copyright © 2019 Alex Griffin <a@ajgrf.com>
;;; Copyright © 2019 Jelle Licht <jlicht@fsfe.org>
;;;
;;; This program is free software: you can redistribute it and/or modify
;;; it under the terms of the GNU General Public License as published by
;;; the Free Software Foundation, either version 3 of the License, or
;;; (at your option) any later version.
;;;
;;; This program is distributed in the hope that it will be useful,
;;; but WITHOUT ANY WARRANTY; without even the implied warranty of
;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
;;; GNU General Public License for more details.
;;;
;;; You should have received a copy of the GNU General Public License
;;; along with this program.  If not, see <https://www.gnu.org/licenses/>.

(define-module (nongnu services my-kernel-modules)
  #:use-module (gnu packages linux)
  #:use-module (gnu services)
  #:use-module (gnu services base)
  #:use-module (gnu services shepherd)
  #:use-module (guix gexp)
  #:use-module (guix records)
  #:use-module (ice-9 match)
  #:export (kernel-modules-configuration
            kernel-modules-configuration?
            kernel-modules-service-type))

(define-record-type* <kernel-modules-configuration>
  kernel-modules-configuration make-kernel-modules-configuration
  kernel-modules-configuration?
  (kmod  kernel-modules-configuration-kmod
         (default kmod))
  (modules kernel-modules-configuration-modules ;list of <package>
           (default '()))
  (names kernel-modules-configuration names ; list of string for modprobe
         (default '())))

(define (modules-directory modules)
  "Return a directory containing MODULES, the OOT kernel modules."
  (directory-union "kernel-modules" modules))

(define kernel-modules-shepherd-service
  (match-lambda
    (($ <kernel-modules-configuration> kmod modules names)
     (let ((modules (modules-directory modules)))
       (list
        (shepherd-service
         (documentation "Load free(?) kernel modules.")
         (requirement '(file-systems))
         (provision '(kernel-modules))
         (one-shot? #t)
         (start
          #~(lambda _
              (define modprobe
                (lambda (name)
                  (zero? (system* "env" (string-append
                                         "LINUX_MODULE_DIRECTORY="
                                         #$(file-append modules "/lib/modules"))
                                  #$(file-append kmod "/bin/modprobe") name))))
              (for-each modprobe (list #$@names))
              #t))))))))

(define kernel-modules-service-type
  (let
      ((config->packages
        (match-lambda
         (($ <kernel-modules-configuration> kmod modules _)
          `(,kmod ,@modules)))))
    (service-type
     (name 'kernel-modules)
     (extensions
      (list (service-extension shepherd-root-service-type
                               kernel-modules-shepherd-service)
            ;; Add kmod and modules to the system profile.
            (service-extension profile-service-type config->packages)))
     (default-value (kernel-modules-configuration))
     (description
      "Load OOT kernel modules."))))
